#include <iostream>
#include <fstream>
#include <string>
#include <unordered_set>
#include <utility>
#include <cmath>
#include <stdio.h>
#include <stdlib.h>
#include <queue>
#include <chrono>
#include "hnswlib.hpp"
#include "vecs_io.hpp"
#include "space_ip.hpp"
#include "hnswalg.hpp"
#include <algorithm>
#include <ctime>
#include <cassert>
#include <omp.h>

int main(int argc, char **argv) {

    if (argc != 6) {
        printf("data_fname output_graph_fname M efConstruction alpha\n");
        return 0;
    }

    std::string dataname = std::string(argv[1]);
    std::string graphname = std::string(argv[2]);
    int M = std::atoi(argv[3]);
    int efConstruction = std::atoi(argv[4]);
    float alpha = std::atof(argv[5]);

    unsigned int vecsize, vecdim;
    float *mass = MIPSGraph::loadVecs<float>(dataname.c_str(), vecsize, vecdim);
    MIPSGraph::InnerProductSpace innerProductSpace(vecdim);

    std::vector<float> element_norms;
    element_norms.reserve(vecsize);
    //计算每一个元素的norm
    for (size_t i = 0; i < vecsize; ++i) {
        float line_norm = 0;
        for (size_t j = 0; j < vecdim; ++j) {
            float ele = mass[i * vecdim + j];
            line_norm += ele * ele;
        }
        line_norm = std::sqrt(line_norm);
        element_norms.push_back(line_norm);
    }

    MIPSGraph::HierarchicalNSW<float> *appr_alg = new MIPSGraph::HierarchicalNSW<float>(&innerProductSpace, vecsize, M,
                                                                                        efConstruction, alpha);

    //将element_norms中的元素移动到对象中, 这样element_norms中就没有元素了
    appr_alg->elementNorms = std::move(element_norms);
    std::cout << "current len element_norms " << element_norms.size() << std::endl;

    std::cout << "Building index\n";
    double t1 = omp_get_wtime();
    for (int i = 0; i < 1; i++) {
        appr_alg->addPoint((void *) (mass + vecdim * i), (size_t) i);
    }
//#pragma omp parallel for
    for (int i = 1; i < vecsize; i++) {
        appr_alg->addPoint((void *) (mass + vecdim * i), (size_t) i);
    }
    double t2 = omp_get_wtime();

    std::cout << "Index built, time=" << t2 - t1 << " s" << "\n";
    appr_alg->SaveIndex(graphname.data());
    delete appr_alg;
    delete mass;
    return 0;
}
